import json
import logging
import re
import time
import uuid
from datetime import datetime
from typing import Any

from fastapi import Request, Depends, HTTPException, Response
from fastapi.responses import JSONResponse
from starlette.responses import StreamingResponse

from datebase import SessionLocal
from models.logModel.LogModel import AmSysWebLog, AmSysApiLog
from models.sysModel.mylab import AmSysUser
from utils.EncryptionUtil import EncryptionMiddleware, TokenVerify, oauth2_scheme
from utils.SecurityUtil import SecurityUtil

logger = logging.getLogger(__name__)


# 鉴权中间件
async def auth_middleware(request: Request, call_next):
    # 定义排除路径和前缀（使用集合提高查找效率）
    EXCLUDED_PATHS = {"/login", "/register", "/token", "/healthcheck"}
    EXCLUDED_PREFIXES = ("/public/", "/static/", "/assets/")  # 不包含 "/docs"
    # 预编译正则表达式
    EXCLUDED_REGEX = re.compile(r"^/docs(/|$)")  # 匹配 /docs 或 /docs/ 开头的路径
    EXCLUDED_REGEX = re.compile(r"^/.*")  # 匹配 /开头的路径

    r1 = any(request.url.path.startswith(prefix) for prefix in EXCLUDED_PREFIXES)
    r2 = request.url.path in EXCLUDED_PATHS
    r3 = EXCLUDED_REGEX.match(request.url.path)
    # 检查排除路径
    if (r1 or r2 or r3):
        return await call_next(request)  # 直接传递请求

    # 鉴权逻辑
    token = await oauth2_scheme(request) if "Authorization" in request.headers else None
    if not token or not token.startswith("Bearer "):
        return JSONResponse(
            content={"message": "没有授权信息", "code": 401},
            status_code=401
        )

    token = token.split(" ")[1]
    try:
        tokenVerify = EncryptionMiddleware.decrypt_token(token)
        request.state.user = tokenVerify
        return await call_next(request)  # 传递给下一个中间件
    except Exception:
        return JSONResponse(
            content={"message": "授权已失效", "code": 401},
            status_code=401
        )


# 请求签名验证中间件
async def signature_verification_middleware(request: Request, call_next):
    # 定义不需要验证签名的路径
    EXCLUDED_PATHS = {"/login", "/public", "/docs"}
    if any(path in request.url.path for path in EXCLUDED_PATHS):
        return await call_next(request)

    # 获取签名和时间戳
    signature = request.query_params.get("sign") or request.headers.get("X-Sign")
    timestamp = request.query_params.get("timestamp") or request.headers.get("X-Timestamp")

    if not signature or not timestamp:
        raise HTTPException(status_code=400, detail="Missing signature or timestamp")

    try:
        timestamp = int(timestamp)
    except ValueError:
        raise HTTPException(status_code=400, detail="Invalid timestamp format")

    # 提取请求数据（不含签名）
    request_data = await SecurityUtil.extract_request_data(request)

    # 验证签名
    if not SecurityUtil.verify_signature(signature, request_data, timestamp):
        raise HTTPException(status_code=401, detail="Invalid signature")

    # 签名验证通过，继续处理请求
    response = await call_next(request)
    return response


# 耗时统计中间件（仅处理耗时，不涉及鉴权） 记录操作日志
async def process_time_middleware(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)  # 等待所有中间件和路由处理完成
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response


# 配置敏感字段过滤正则（不区分大小写）
SENSITIVE_FIELDS = re.compile(r'(password)', re.IGNORECASE)


# 请求中间件
async def log_requests(request: Request, call_next):
    db = SessionLocal()
    method = request.method
    path = request.scope["path"]
    service_name = request.app.openapi_tags
    query_params = dict(request.query_params)
    client_ip = request.client.host if request.client else "unknown"
    user_id = 0
    user_name = ""
    token = ""
    if request.headers.get("Authorization"):
        token = request.headers.get("Authorization")
        token = token.split(" ")[1]
        user = EncryptionMiddleware.get_current_username(token)
        user_name = user["user_name"]
        user_id = user["user_id"]

    request_logger = logging.getLogger('request')
    api_logger = logging.getLogger('api')
    start_time = time.time()

    # ---------------------- 获取请求参数和体 ----------------------
    request_body = {}
    if request.method in ("POST", "PUT", "PATCH", "DELETE"):
        content_type = request.headers.get("content-type", "")
        try:
            if "application/json" in content_type:
                request_body = await request.json()
            elif "multipart/form-data" in content_type:
                form_data = await request.form()
                request_body = dict(form_data)
            elif "application/x-www-form-urlencoded" in content_type:
                form_data = await request.form()
                request_body = dict(form_data)
            else:
                raw_body = await request.body()
                request_body = raw_body.decode("utf-8", errors="replace") if raw_body else ""
        except Exception as e:
            request_body = f"<Error parsing request body: {str(e)}>"

    # ---------------------处理响应--------------------------------
    response = await call_next(request)

    EXCLUDED_PATHS = {"/docs", "/openapi.json"}
    r2 = request.url.path in EXCLUDED_PATHS
    # 初始化响应体收集器
    response_body = b""
    json_response = None
    status_code = response.status_code
    if r2:
        json_response = None
    else:
        # 复制原始响应属性
        response_headers = dict(response.headers)
        try:
            # 收集响应体
            async for chunk in response.body_iterator:
                if chunk:
                    response_body += chunk
            # 尝试解析JSON
            if "application/json" in response_headers.get("content-type", ""):
                try:
                    json_response = json.loads(response_body.decode())
                except json.JSONDecodeError:
                    json_response = {"error": "Invalid JSON response"}
        except Exception as e:
            logging.error(f"Error processing response: {str(e)}", exc_info=True)
            json_response = {"error": "Response processing failed"}

        # 重建响应
        if json_response is not None:
            response = JSONResponse(
                content=json_response,
                status_code=status_code,
                headers=response_headers
            )
        else:
            # 非JSON响应直接返回原始内容
            response = Response(
                content=response_body,
                status_code=status_code,
                headers=response_headers,
                media_type=response_headers.get("content-type")
            )
    # ---------------------- 计算请求耗时 ----------------------
    create_time = datetime.now()
    response_time = int((time.time() - start_time) * 1000)

    # 持久化到数据库
    try:
        with db.begin():
            web_log = AmSysWebLog(
                create_time=create_time,
                method=f"{method}:{path}",
                user_id=user_id,
                ip=client_ip,
                service_name=str(service_name),
                user_name=user_name,
                operation_desc="",
                params=str(query_params)
            )
            db.add(web_log)

            api_log = AmSysApiLog(
                create_time=create_time,
                method=f"{method}:{path}",
                user_id=user_id,
                ip=client_ip,
                service_name=str(service_name),
                user_name=user_name,
                operation_desc="",
                params=token
            )
            db.add(api_log)

    except Exception as e:
        logging.error(f"Database error: {str(e)}", exc_info=True)
    finally:
        db.close()

    # 记录日志 操作日志
    log_data = {
        'client_ip': client_ip,
        'method': method,
        'path': path,
        'user_id': user_id,
        'status_code': status_code,
        'response_time': response_time,
        'query_params': query_params,
        'request_body': request_body,
        'response_body': json_response if json_response is not None else response_body.decode(errors='replace')
    }
    api_data = {
        'client_ip': client_ip,
        'method': method,
        'path': path,
        'user_id': user_id,
        'status_code': status_code,
        'response_time': response_time,
        'query_params': query_params,
        'request_body': request_body,
        'response_body': json_response if json_response is not None else response_body.decode(errors='replace')
    }
    request_logger.info("Request processed", extra=log_data)
    api_logger.info("Request processed", extra=api_data)

    return response
